/*
 * 落地器模块扩展
 *
 **/

#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <memory>
#include <unordered_map>
#if defined (WIN32) || defined (WIN64)
#   include "../easysock.h"
#elif defined (__linux__) || defined (__APPLE__)
#   include <easysock.h>
#endif
#include "config.hpp"
#include "level.hpp"
#include "message.hpp"
#include "format.hpp"
#include "util.hpp"
#include "sink.hpp"

namespace easylog
{

class tcp_sink : public sinker
{
public:
    tcp_sink(const std::string& sip     = "47.101.68.49",
                       uint16_t sport   = 8888,
                            int trytime = 1,
                 formatter::ptr fmter   = std::make_shared<formatter>())
        : sinker(fmter)
        , _cli(inet::api::useip, sip, sport, trytime)
    {
        fmter->set_pattern(R"(
"time": "%d{%F %H:%M:%S}",
"level": "%p",
"file": "%f",
"line": "%l",
"func": "%a",
"tid": "%t",
"lname": "%c",
"payload": "%s")");
    }

    virtual void sink(message&& msg) override
    {
        std::string data = _fmtr->format(std::forward<message>(msg));
        _cli.send(data);
    }

protected:
    inet::tcp::client _cli;
};

const std::string    default_server_ip    = "47.98.207.80";
const uint16_t       default_server_port  = 8888;
const std::string    default_sms_uri      = "/sms.aspx";
const std::string    default_action       = "send";
const std::string    default_user_id      = "6465";
const std::string    default_account      = "码农烧烤";
const std::string    default_password     = "501200";
const std::string    default_project_name = "easylog";
const std::string    default_text_pattern = "【码农烧烤】开发者您好，%s项目的日志器%s发起一条%s级的日志，具体如下：\n%s";
const level::lv_enum default_remind_level = level::error;
const std::string    default_phone        = "17315380532, 15952699923";


class sms_sink : public sinker
{
public:
    sms_sink(const std::string& server_ip    = default_server_ip,
                       uint16_t server_port  = default_server_port,
             const std::string& sms_uri      = default_sms_uri,
             const std::string& action       = default_action,
             const std::string& userid       = default_user_id,
             const std::string& account      = default_account,
             const std::string& password     = default_password,
             const std::string& project_name = default_project_name,
             const std::string& text_pattern = default_text_pattern,
                 level::lv_enum remind_level = default_remind_level,
             const std::string& phone_number = default_phone,
                 formatter::ptr fmter        = std::make_shared<formatter>())
        : sinker(fmter)
        , _server_ip(server_ip)
        , _server_port(server_port)
        , _sms_uri(sms_uri)
        , _action(action)
        , _userid(userid)
        , _account(account)
        , _password(password)
        , _project_name(project_name)
        , _text_pattern(text_pattern)
        , _remind_level(remind_level)
        , _phone_number(phone_number)
    {}

    virtual void sink(message&& msg) override
    {
        if (msg.levo < _remind_level)
            return;

        std::unique_ptr<char[]> res(new char[256]{0});
        if (snprintf(res.get(),
                     255,
                     _text_pattern.c_str(),
                     _project_name.c_str(),
                     msg.lname.c_str(),
                     level::level2str(msg.levo).c_str(),
                     _fmtr->format(std::forward<message>(msg)).c_str()) == -1)
        {
            throw except("sms sink snprintf error");
        }

        std::string content = "action=" + _action
                            + "&userid=" + _userid
                            + "&account=" + _account
                            + "&password=" + _password
                            + "&mobile=" + _phone_number
                            + "&content=" + res.get();

        std::string requset = "POST " + _sms_uri + " HTTP/1.0\n"
                            + "Content-Type: application/x-www-form-urlencoded\n"
                            + "Content-Length: "
                            + std::to_string(content.size()) + "\n\n" + content;

        if (inet::tcp::client(inet::api::useip, _server_ip, _server_port).send(requset) <= 0)
            throw except("sms sink send request error");
    }

protected:
    std::string _server_ip;
    uint16_t    _server_port;
    std::string _sms_uri;
    std::string _action;
    std::string _userid;
    std::string _account;
    std::string _password;
    std::string _project_name;
    level::lv_enum _remind_level;
    std::string _text_pattern;
    std::string _phone_number;
};

}
